﻿(function() {

  $.widget("ui.combobox", {
    options: {
      source: null,
      name: '',
      isDynamic: false,
      isMulti: false,
      valueSource: null,
      values: null
    },
    _create: function() {
      var url,
        _this = this;
      if (this.options.isMulti && !this.options.isDynamic) {
        this.buildMultiAutocomplete();
        return;
      }
      if (this.options.isMulti && this.options.isDynamic) {
        this.buildMultiAutocomplete();
        return;
      }
      if (!this.options.isMulti && !this.options.isDynamic && (this.options.source != null)) {
        url = this.options.source;
        this.options.source = null;
        $.ajax({
          url: url,
          dataType: "json",
          success: function(data) {
            var item, _i, _len;
            for (_i = 0, _len = data.length; _i < _len; _i++) {
              item = data[_i];
              if (item.Selected) {
                $(_this.element).append("<option selected='selected' value='" + item.Value + "'>" + item.Text + "</option>");
              } else {
                $(_this.element).append("<option value='" + item.Value + "'>" + item.Text + "</option>");
              }
            }
            return _this.buildSingleAutocomplete();
          }
        });
        return;
      }
      if (!this.options.isMulti && !this.options.isDynamic && !(typeof source !== "undefined" && source !== null)) {
        this.buildSingleAutocomplete();
        return;
      }
      if (!this.options.isMulti && this.options.isDynamic) {
        this.buildSingleAutocomplete();
      }
    },
    destroy: function() {
      this.wrapper.remove();
      this.items.remove();
      this.element.show();
      return $.Widget.prototype.destroy.call(this);
    },
    buildSingleAutocomplete: function() {
      var input, items, select, selected, that, value, wrapper;
      that = this;
      select = this.element.hide();
      if (that.options.isDynamic) {
        select.attr("name", "_" + (select.attr('name')));
      }
      selected = select.children(":selected");
      value = selected.val() ? selected.text() : "";
      wrapper = this.wrapper = $("<span>").addClass("ui-combobox").insertAfter(select);
      items = this.items = $('<div class="multiselect-items"></div>').appendTo(wrapper.parent());
      input = $("<input>");
      input.appendTo(wrapper);
      input.val(value);
      input.attr("title", "");
      input.addClass('ui-state-default ui-combobox-input');
      input.autocomplete({
        delay: 0,
        minLength: 0,
        source: function(request, response) {
          var matcher;
          if (that.options.isDynamic) {
            return $.get(that.options.source, {
              term: request.term
            }, function(data) {
              var item, lastOption, result, _i, _len;
              result = [];
              select.children("option").remove();
              for (_i = 0, _len = data.length; _i < _len; _i++) {
                item = data[_i];
                select.append("<option value=" + item.id + ">" + item.value + "</option>");
                lastOption = select.find("option:last-child");
                result.push({
                  option: lastOption,
                  label: item.label,
                  value: item.value
                });
              }
              return response(result);
            });
          } else {
            matcher = new RegExp($.ui.autocomplete.escapeRegex(request.term), "i");
            return response(select.children("option").not(':disabled').map(function() {
              var text;
              text = $(this).text();
              if (this.value && (!request.term || matcher.test(text))) {
                return {
                  label: text.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + $.ui.autocomplete.escapeRegex(request.term) + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>"),
                  value: text,
                  option: this
                };
              }
            }));
          }
        },
        select: function(event, ui) {
          var currentOption, option;
          ui.item.option.selected = true;
          that._trigger("selected", event, {
            item: ui.item.option
          });
          select.closest("fieldset > div").trigger("validate");
          if (that.options.isDynamic) {
            ui.item.option.selected = false;
            currentOption = items.find("input");
            if (currentOption != null) {
              option = currentOption.closest('select').find("option[value='" + (currentOption.val()) + "']");
            }
            currentOption = $(ui.item.option);
            currentOption.removeAttr('selected');
            items.html("<input type='hidden' name='" + (select.attr("name").replace("_", "")) + "' value='" + (currentOption.val()) + "' />");
            return select.val("");
          }
        },
        change: function(event, ui) {
          if (!ui.item) {
            return that.removeIfInvalid(this, input);
          }
        }
      });
      this.addLink(input);
      this.modifyImput(input);
      if (this.options.isDynamic && (this.options.valueSource != null)) {
        return $.ajax({
          url: this.options.valueSource,
          method: "GET",
          dataType: "json",
          success: function(value) {
            if (value != null) {
              items.html("<input type='hidden' name='" + (select.attr("name").replace("_", "")) + "' value='" + value.Id + "' />");
              input.val(value.Value);
            }
          }
        });
      }
    },
    buildMultiAutocomplete: function() {
      var input, items, select, selected, that, value, wrapper;
      that = this;
      select = this.element.hide();
      selected = select.children(":selected");
      value = selected.val() ? selected.text() : "";
      wrapper = this.wrapper = $("<span>").addClass("ui-combobox").insertAfter(select);
      items = this.items = $('<ul class="multiselect-items"></ul>').appendTo(wrapper.parent());
      input = $("<input>");
      input.appendTo(wrapper);
      input.val(value);
      input.attr("title", "");
      input.addClass('ui-state-default ui-combobox-input');
      input.autocomplete({
        delay: 0,
        minLength: 0,
        source: function(request, response) {
          var matcher;
          if (that.options.isDynamic) {
            return $.get(that.options.source, {
              term: request.term
            }, function(data) {
              var item, lastOption, result, _i, _len;
              result = [];
              select.children("option").remove();
              for (_i = 0, _len = data.length; _i < _len; _i++) {
                item = data[_i];
                if (items.find("input[value=" + item.id + "]").length === 0) {
                  select.append("<option value=" + item.id + ">" + item.value + "</option>");
                  lastOption = select.find("option:last-child");
                  result.push({
                    option: lastOption,
                    label: item.label,
                    value: item.value
                  });
                }
              }
              return response(result);
            });
          } else {
            matcher = new RegExp($.ui.autocomplete.escapeRegex(request.term), "i");
            return response(select.children("option").not(':disabled').map(function() {
              var text;
              text = $(this).text();
              if (this.value && (!request.term || matcher.test(text))) {
                return {
                  label: text.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + $.ui.autocomplete.escapeRegex(request.term) + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>"),
                  value: text,
                  option: this
                };
              }
            }));
          }
        },
        select: function(event, ui) {
          var currentOption;
          ui.item.option.selected = false;
          that._trigger("selected", event, {
            item: ui.item.option
          });
          currentOption = $(ui.item.option);
          currentOption.attr('disabled', 'disabled');
          currentOption.removeAttr('selected');
          items.append(("<li><input type='hidden' name='" + (select.attr("name")) + "' value='" + (currentOption.val()) + "' />") + ("<span>" + (currentOption.text()) + "</span><a class='remove no-link' href='#'></a>") + "</li>");
          $(this).closest("fieldset>div").trigger("validate");
          items.find('li:last-child').find('a').on('click', function(event) {
            var div, option;
            event.preventDefault();
            option = currentOption.closest('select').find("option[value='" + (currentOption.val()) + "']");
            option.removeAttr('disabled');
            div = $(this).closest("fieldset>div");
            $(this).closest('li').remove();
            return $(div).trigger("validate");
          });
        },
        change: function(event, ui) {
          if (!ui.item) {
            return that.removeIfInvalid(this, input);
          }
        },
        close: function(event, ui) {
          select.val("");
          return input.val("");
        }
      });
      this.addLink(input);
      this.modifyImput(input);
      if (this.options.isMulti && this.options.isDynamic && (this.options.valueSource != null)) {
        $.ajax({
          url: this.options.valueSource,
          method: "GET",
          dataType: "json",
          success: function(values) {
            _.each(values, function(value) {
              items.append("<li><input type='hidden' style='display: none' name='" + (select.attr("name")) + "' value='" + value.Value + "' /><span>" + value.Text + "</span><a class='remove no-link' href='#'></a></li>");
              items.find('li:last-child').find('a').on('click', function(event) {
                var div;
                event.preventDefault();
                div = $(this).closest("fieldset>div");
                $(this).closest('li').remove();
                return $(div).trigger("validate");
              });
            });
          }
        });
      }
      if (this.options.isMulti && !this.options.isDynamic && (this.options.values != null)) {
        _.each(this.options.values, function(value) {
          var option;
          option = select.find("option[value='" + value + "']");
          option.attr("disabled", "disabled");
          items.append("<li><input type='hidden' style='display: none' name='" + (select.attr("name")) + "' value='" + value + "' /><span>" + (option.text()) + "</span><a class='remove no-link' href='#'></a></li>");
          option.removeAttr("selected");
          return items.find('li:last-child').find('a').on('click', function(event) {
            var div;
            event.preventDefault();
            option = option.closest('select').find("option[value='" + (option.val()) + "']");
            option.removeAttr('disabled');
            div = $(this).closest("fieldset>div");
            $(this).closest('li').remove();
            return $(div).trigger("validate");
          });
        });
        return input.val('');
      }
    },
    removeIfInvalid: function(element, input) {
      var matcher, select, valid, value;
      select = this.element.hide();
      value = $(element).val();
      matcher = new RegExp("^" + $.ui.autocomplete.escapeRegex(value) + "$", "i");
      valid = false;
      select.children("option").each(function() {
        if ($(this).text().match(matcher)) {
          this.selected = valid = true;
          return false;
        }
      });
      if (!valid) {
        $(element).val("").attr("title", value + " didn't match any item").tooltip("open");
        select.val('');
        setTimeout(function() {
          return input.tooltip("close").attr("title", '');
        }, 2500);
        input.data("autocomplete").term = '';
        return false;
      }
    },
    addLink: function(input) {
      var link, that;
      that = this;
      link = $("<a>");
      link.attr("tabIndex", -1);
      link.attr("title", "Show All Items");
      link.tooltip();
      link.appendTo(this.wrapper);
      link.button({
        icons: {
          primary: "ui-icon-triangle-1-s"
        },
        text: false
      });
      link.removeClass("ui-corner-all");
      link.addClass("ui-corner-right ui-combobox-toggle no-link");
      return link.click(function() {
        if (input.autocomplete("widget").is(":visible")) {
          input.autocomplete("close");
          that.removeIfInvalid(input);
          return;
        }
        $(this).blur();
        input.autocomplete("search", "");
        return input.focus();
      });
    },
    modifyImput: function(input) {
      input.data("autocomplete")._renderItem = function(ul, item) {
        return $("<li>").data("item.autocomplete", item).append("<a>" + item.label + "</a>").appendTo(ul);
      };
      return input.tooltip({
        position: {
          of: this.button
        },
        tooltipClass: "ui-state-highlight"
      });
    }
  });

}).call(this);
